package com.ultimatetech.cim.dialogs;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import javax.wbem.cim.CIMClass;
import javax.wbem.cim.CIMDataType;
import javax.wbem.cim.CIMDateTime;
import javax.wbem.cim.CIMException;
import javax.wbem.cim.CIMInstance;
import javax.wbem.cim.CIMProperty;
import javax.wbem.cim.CIMValue;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

import com.ultimatetech.cim.CIMPlugin;



public class NewInstanceDialog extends Dialog {
	
//	private List changedProps = null;
    private static String COLUMN_NAMES[] = new String[] { 
        "Property Name", "Value", "Data Type" };

	private List<String> keysList = null;
	private Composite tableComp = null;
	private TableViewer viewer = null;
	private CIMClass cimClass = null;
	
	private CIMInstance cimInstance;
	public NewInstanceDialog(Shell parentShell, CIMClass cc)
	{
		super(parentShell);
		cimClass = cc;
		cimInstance = cimClass.newInstance();
		/* new CIMInstance();		
		cimInstance.setProperties(cc.getAllProperties());*/
		keysList = new ArrayList<String>();
		Vector<CIMProperty> v = cimClass.getKeys();
		int sz1 = v == null ? 0 : v.size();
		for(int i = 0; i < sz1; i++){
			CIMProperty cp = (CIMProperty)v.get(i);
			keysList.add(cp.getName());
		}
	}
	
	protected Control createDialogArea(Composite parent) {		
		Composite composite = (Composite)super.createDialogArea(parent);
		createInstanceTable(composite);		
		return composite;
	}

	/**
	 * @param parent
	 */
	private void createInstanceTable(Composite parent) {
		tableComp = new Composite(parent, SWT.BORDER |SWT.FILL);
		FillLayout fl = new FillLayout();		
		tableComp.setLayout(fl);
		GridData gld = new GridData();
		gld.grabExcessHorizontalSpace = true;
		gld.grabExcessVerticalSpace = true;
		gld.horizontalAlignment = SWT.FILL;
		gld.verticalAlignment = SWT.FILL;
		gld.heightHint=250;
		gld.widthHint = 600;
		tableComp.setLayoutData(gld);
		viewer = new TableViewer(tableComp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
		ViewContentProvider vcp = new ViewContentProvider();
		viewer.setContentProvider(vcp);
		addTableColumns(viewer.getTable());
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setSorter(new NameSorter());
		viewer.setInput(cimClass.getAllProperties().toArray());		
		
		viewer.getTable().setHeaderVisible(true);		
		viewer.setColumnProperties(COLUMN_NAMES);
		addTableCellEditors();
	}
	private void addTableColumns(Table objectPathTable){
		TableColumn column = new TableColumn(objectPathTable, SWT.LEFT, 0);		
		column.setText(COLUMN_NAMES[0]);
		column.setWidth(120);
		column = new TableColumn(objectPathTable, SWT.LEFT, 1);
		column.setText(COLUMN_NAMES[1]);
		column.setWidth(400);
		column = new TableColumn(objectPathTable, SWT.LEFT, 2);
		column.setText(COLUMN_NAMES[2]);
		column.setWidth(100);
		objectPathTable.setLinesVisible(true);
		/*CellEditor[] editors = new CellEditor[COLUMN_NAMES.length];
		editors[0] = new TextCellEditor(objectPathTable);
		editors[1] = new TextCellEditor(objectPathTable);
		editors[2] = new TextCellEditor(objectPathTable);
		viewer.setCellEditors(editors);
		viewer.setCellModifier(new InstanceCellModifier());*/
	}	
	
	public CIMInstance getCIMInstance() {
		return cimInstance;
	}
	
	class ViewContentProvider implements IStructuredContentProvider {
		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
		}
		public void dispose() {
		}
		public Object[] getElements(Object parent) {
			if(cimClass != null){
				Vector<CIMProperty> v = cimClass.getAllProperties();
				return v.toArray();
			}
			return new String[] { "Right click on the class in CIM Explorer to create new instance" };
		}
	}
	class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
		public String getColumnText(Object obj, int index) {
			String result = "";
			if(obj instanceof CIMProperty) {
			CIMProperty cop = (CIMProperty) obj;
			
			switch (index) {
				case 0: 
					result = cop.getName();
					break;
				case 1 :
					result = cimInstance.getProperty(cop.getName()) == null ? 
							"<enter value>" : 
								cimInstance.getProperty(cop.getName()).getValue() == null ?
										"<enter value>" : cimInstance.getProperty(cop.getName()).getValue().toMOF();
					break;							
				case 2 :
					result = cop.getType() == null ? "null" : cop.getType().toMOF();
					break;
				default :
					break; 	
			}
			}
			return result;	
		}
		public Image getColumnImage(Object obj, int index) {
			if(index == 0 && obj instanceof CIMProperty){
				CIMProperty cop = (CIMProperty) obj;
				String name = cop.getName();				
				if(keysList != null && keysList.contains(name)){
					return getImage(obj);	
				}
				
			}
			return null;
		}
		public Image getImage(Object obj) {
			
			return CIMPlugin.getDefault().getImage("icons/key.gif");
			
		}
	}
	class NameSorter extends ViewerSorter {
	}
	
	/*class InstanceCellModifier implements ICellModifier {

		public boolean canModify(Object element, String property) {
			if(property.equals(COLUMN_NAMES[1])){
				return true;
			}
			return false;
		}

		public Object getValue(Object element, String property) {
			CIMProperty cop = (CIMProperty) element;
			if(property.equals(COLUMN_NAMES[0])){
				return cop.getName();
			} else if(property.equals(COLUMN_NAMES[1])){
				return cimInstance.getProperty(cop.getName()) == null ? 
						"<enter value>" : cimInstance.getProperty(cop.getName()).toString();
			} else if(property.equals(COLUMN_NAMES[2])){
				return cop.getType().toMOF();
			}
			
			return null;
		}

		public void modify(Object element, String property, Object value) {
			TableItem ti = (TableItem)element;
			CIMProperty cp = (CIMProperty)ti.getData();
 			if(property.equals(COLUMN_NAMES[1])){
				CIMValue cv = new CIMValue(value);
				try {
					cimInstance.setProperty(cp.getName(), cv);
					viewer.refresh();
				} catch (CIMException e) {
					ErrorDialog ed = new ErrorDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
							"Error", "Set value failed:" + e.getMessage(), 
							new Status(Status.ERROR, "CIMPlugin", e.getXmlCode(e.getID()), e.getMessage(), e),
							IStatus.ERROR);
					ed.open();
				}
			}
			
		}
		
	}*/
	
	
	
	private void addTableCellEditors() {
		final Table table = viewer.getTable();
		final TableEditor te = new TableEditor(table);
		te.grabHorizontal = true;
		te.horizontalAlignment = SWT.LEFT;
		table.addListener(SWT.MouseDown, new Listener() {
			public void handleEvent(Event event) {
			Rectangle clientArea = table.getClientArea();
	        Point pt = new Point(event.x, event.y);
	        int index = table.getTopIndex();
	        while (index < table.getItemCount()) {
	            boolean visible = false;
	            final TableItem item = table.getItem(index);
	            //for (int i = 0; i < table.getColumnCount(); i++) {
	            	int i = 1; //edit only value
	              Rectangle rect = item.getBounds(i);
	              if (rect.contains(pt)) {
	                final int column = i;
	                final Text text = new Text(table, SWT.NONE);
	                Listener textListener = new Listener() {
	                  public void handleEvent(final Event e) {
	                    switch (e.type) {
	                    case SWT.FocusOut:
	                    	setCIMValue(item, text);
	                      item.setText(column, text.getText());
	                      text.dispose();
	                      //setInstanceAct.setEnabled(true);
	                      break;
	                    case SWT.Traverse:
	                      switch (e.detail) {
	                      case SWT.TRAVERSE_RETURN:
	                    	  
	                        item
	                            .setText(column, text
	                                .getText());
	                        //setInstanceAct.setEnabled(true);
	                        setCIMValue(item, text);
	                      //FALL THROUGH
	                      case SWT.TRAVERSE_ESCAPE:
	                        text.dispose();
	                        e.doit = false;	                        
	                      }
	                      break;
	                    }
	                  }

					/**
					 * @param item
					 * @param text
					 */
					private void setCIMValue(final TableItem item, final Text text) {
						CIMProperty cip = (CIMProperty)item.getData();
						//CIMProperty cp = new CIMProperty(cip.getName());
						String newVal = text.getText();
						CIMDataType cdt = cip.getType();
//						if(changedProps == null){
//							changedProps = new ArrayList();
//						}
						//changedProps.add(cp.getName());
						try {
							if(cdt.isArrayType()){
								String vals[] = newVal.split(",");
								if(cdt.getType() == CIMDataType.STRING_ARRAY){
									CIMValue newCimVal = new CIMValue(newVal, cdt);							
									//cp.setValue(newCimVal);
									cimInstance.setProperty(cip.getName(), newCimVal);
								} else {
									Vector v = new Vector(vals.length);
									for(int i = 0; i < vals.length; i++){
										if(cdt.getType() == CIMDataType.UINT8_ARRAY || 	                    		
												cdt.getType() == CIMDataType.UINT16_ARRAY ||
												cdt.getType() == CIMDataType.UINT32_ARRAY) {
											v.add(new Integer(vals[i]));
										} else if(cdt.getType() == CIMDataType.DATETIME_ARRAY){
											v.add(new CIMDateTime(vals[i]));
										}
									}
									CIMValue newCimVal = new CIMValue(v);
									//cp.setValue(newCimVal);
									cimInstance.setProperty(cip.getName(), newCimVal);
								}
							} else {
								CIMValue newCimVal = null;
								if(cdt.getType() == CIMDataType.STRING){
									newCimVal = new CIMValue(newVal, cdt);
									
								} else if(cdt.getType() == CIMDataType.BOOLEAN){
									newCimVal = new CIMValue(new Boolean(newVal), cdt);
								} else if(cdt.getType() == CIMDataType.UINT8_ARRAY || 	                    		
										cdt.getType() == CIMDataType.UINT16_ARRAY ||
										cdt.getType() == CIMDataType.UINT32_ARRAY){
									newCimVal = new CIMValue(new Integer(newVal));
								} else if(cdt.getType() == CIMDataType.DATETIME){
									newCimVal = new CIMValue(new CIMDateTime(new Date(newVal)));
								} else if(cdt.getType() == CIMDataType.REFERENCE){
									showMessage("Reference value not supported yet...");
								}
								cimInstance.setProperty(cip.getName(), newCimVal);
							}
						} catch (NumberFormatException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IllegalArgumentException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (CIMException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
	                };
	                text.addListener(SWT.FocusOut, textListener);
	                text.addListener(SWT.Traverse, textListener);
	                te.setEditor(text, item, i);
	                text.setText(item.getText(i));
	                text.selectAll();
	                text.setFocus();
	                return;
	              }
	              if (!visible && rect.intersects(clientArea)) {
	                visible = true;
	              }
	            //}
	            if (!visible)
	              return;
	            index++;
	          }
			}
		});
	}
	
	private void showMessage(String message) {
		MessageDialog.openInformation(
			viewer.getControl().getShell(),
			"New Instance",
			message);
	}
	
	
}
